#include "Avalon/SignalHandling/SignalSink.hpp"
#include "Avalon/Base/Algorithm.hpp"

using namespace Avalon;
using namespace Avalon::SignalHandling;
using namespace boost;
using namespace boost::signals2;
using namespace boost::posix_time;
using namespace std;

SignalSink::SignalEntry::SignalEntry(const type_info& type,
    const vector<any>& parameters)
    : m_type(&type),
      m_parameters(parameters) {}

SignalSinkPtr SignalSink::Create() {
  return SignalSinkPtr(new SignalSink());
}

SignalSink::~SignalSink() {}

SignalSink::SignalEntry SignalSink::GetNextSignal(time_duration timeout) {
  boost::unique_lock<boost::mutex> lock(m_mutex);
  if(m_signalEntries.empty()) {
    if(timeout == pos_infin) {
      m_signalEmptyCondition.wait(lock);
    } else if(!m_signalEmptyCondition.timed_wait(lock, timeout)) {
      BOOST_THROW_EXCEPTION(runtime_error("Signal timed out."));
    }
  }
  SignalEntry entry = m_signalEntries.front();
  m_signalEntries.pop_front();
  return entry;
}

SignalSink::SignalSink() {}

void SignalSink::Slot() {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  m_signalEntries.push_back(SignalEntry(typeid(signals2::signal<void ()>),
    vector<any>()));
  if(m_signalEntries.size() == 1) {
    m_signalEmptyCondition.notify_all();
  }
}
